package com.gzx.plugin.tjzy.modular.call.predict.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.gzx.plugin.tjzy.modular.call.api.service.GzxHtCallApiService;
import com.gzx.plugin.tjzy.modular.call.pre.enums.GzxBatchStatusEnum;
import com.gzx.plugin.tjzy.modular.call.predict.consts.GzxHtSwitchTaskType;
import com.gzx.plugin.tjzy.modular.call.predict.entity.GzxPredictCall;
import com.gzx.plugin.tjzy.modular.call.predict.entity.GzxPredictCallDetail;
import com.gzx.plugin.tjzy.modular.call.predict.enums.GzxCallBatchStatusEnum;
import com.gzx.plugin.tjzy.modular.call.predict.service.GzxPredictCallDbService;
import com.gzx.plugin.tjzy.modular.call.predict.service.GzxPredictCallXxlService;
import com.gzx.plugin.tjzy.modular.phone.complaint.service.GzxComplaintPhoneService;
import com.gzx.plugin.tjzy.modular.phone.dto.GzxPhoneStatusDto;
import com.gzx.plugin.tjzy.modular.phone.error.service.GzxErrorPhoneService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import vip.xiaonuo.common.consts.IntConstant;
import vip.xiaonuo.common.util.CommonDateUtil;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zjt
 * @description
 * @date 2025/6/9 18:22
 */
@Service
@RequiredArgsConstructor
public class GzxPredictCallXxlServiceImpl implements GzxPredictCallXxlService {

    private final GzxPredictCallDbService predictCallDbService;

    private final GzxHtCallApiService predictHttpService;

    private final GzxComplaintPhoneService complaintPhoneService;

    private final GzxErrorPhoneService errorPhoneService;

    /**
     * 校准预测批次
     *
     * @param deptId
     */
    @Override
    public void modifyBatchStatusAndCount(String deptId) {
        List<GzxPredictCall> predictCallList = predictCallDbService.selectList(Wrappers.<GzxPredictCall>lambdaQuery()
                .select(GzxPredictCall::getTaskId)
                .eq(GzxPredictCall::getCreateDept, deptId)
                .in(GzxPredictCall::getBatchStatus, GzxBatchStatusEnum.IN_PROGRESS.getCode()));
        if (CollectionUtil.isNotEmpty(predictCallList)) {
            List<String> sortedTaskIdList = predictCallList.stream()
                    .map(GzxPredictCall::getTaskId)
                    .distinct()
                    .sorted()
                    .toList();
            predictCallDbService.modifyBatchStatusAndCount(sortedTaskIdList);
        }
    }

    /**
     * 预测外呼任务完结
     */
    @Override
    public void finishCallTask() {
        //查询今天的预测外呼任务的
        List<GzxPredictCall> predictCallList = predictCallDbService.selectList(Wrappers.<GzxPredictCall>lambdaQuery()
                .select(GzxPredictCall::getId, GzxPredictCall::getTaskId)
                .between(GzxPredictCall::getCreateTime, CommonDateUtil.getOffsetDateStr(-3) + " 00:00:00", CommonDateUtil.getOffsetDateStr(-3) + " 23:59:59"));
        if (CollectionUtil.isNotEmpty(predictCallList)) {
            Set<String> taskIdSet = predictCallList.stream().map(GzxPredictCall::getTaskId).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
            for (String taskId : taskIdSet) {
                predictHttpService.switchTask(taskId, GzxHtSwitchTaskType.FINISH);
            }
            List<Long> idList = predictCallList.stream().map(GzxPredictCall::getId).toList();
            predictCallDbService.update(Wrappers.<GzxPredictCall>lambdaUpdate()
                    .setSql("batch_status = if(total_count = completed_count, 3, 4)")
                    .in(GzxPredictCall::getId, idList));
        }
    }

    /**
     * 校验预测外呼数据
     */
    @Override
    public void verifyData() {
        List<GzxPredictCall> predictCallList = predictCallDbService.selectList(Wrappers.<GzxPredictCall>lambdaQuery()
                .select(GzxPredictCall::getId, GzxPredictCall::getBatchNumber, GzxPredictCall::getCallName, GzxPredictCall::getCreateUser, GzxPredictCall::getTenantId)
                .eq(GzxPredictCall::getBatchStatus, GzxCallBatchStatusEnum.CHECKING.getCode()));
        if (CollectionUtil.isNotEmpty(predictCallList)) {
            Map<String, GzxPredictCall> batchNumberMap = predictCallList.stream()
                    .collect(Collectors.toMap(
                            GzxPredictCall::getBatchNumber,
                            Function.identity()));
            //修改为校验中
            predictCallDbService.update(Wrappers.<GzxPredictCall>lambdaUpdate()
                    .set(GzxPredictCall::getBatchStatus, GzxCallBatchStatusEnum.IN_CHECKING.getCode())
                    .in(GzxPredictCall::getBatchNumber, batchNumberMap.keySet()));
            for (Map.Entry<String, GzxPredictCall> entry : batchNumberMap.entrySet()) {
                //查询所有手机号
                List<GzxPredictCallDetail> predictCallDetailList = predictCallDbService.selectDetailList(Wrappers.<GzxPredictCallDetail>lambdaQuery()
                        .select(GzxPredictCallDetail::getId, GzxPredictCallDetail::getLiaisonPhone)
                        .eq(GzxPredictCallDetail::getBatchNumber, entry.getKey()));
                List<String> liaisonPhoneList = predictCallDetailList.stream().map(GzxPredictCallDetail::getLiaisonPhone).toList();
                //验证投诉投诉手机号
                List<GzxPhoneStatusDto> complaintPhoneStatusDtoList = verifyComplaintPhone(liaisonPhoneList, entry.getValue().getCreateUser(), entry.getValue().getTenantId());
                //根据结果进行分组
                Map<Integer, List<String>> complaintPhoneMap = complaintPhoneStatusDtoList.stream()
                        .collect(Collectors.groupingBy(
                                GzxPhoneStatusDto::getType,
                                Collectors.mapping(
                                        GzxPhoneStatusDto::getPhone,
                                        Collectors.toList())));
                //手机号转ID，用ID（主键）进行删除或者修改，性能更高
                Set<Long> needDeletePhoneIdList = new HashSet<>();
                Map<Integer, List<Long>> complaintPhoneIdMap = phoneToList(complaintPhoneMap, predictCallDetailList);
                //判断对于名单用户是需要删除还是修改
                if (complaintPhoneIdMap.containsKey(1) && !entry.getValue().getCallName().contains("三方")) {
                    needDeletePhoneIdList.addAll(complaintPhoneIdMap.get(1));
                }
                List<GzxPhoneStatusDto> errorPhoneStatusDtoList = verifyErrorPhone(liaisonPhoneList, entry.getValue().getCreateUser(), entry.getValue().getTenantId());
                List<String> errorPhoneList = errorPhoneStatusDtoList.stream().filter(s -> s.getType() > 0).map(GzxPhoneStatusDto::getPhone).toList();
                if (CollectionUtil.isNotEmpty(errorPhoneList)) {
                    List<Long> errorPhoneIdList = phoneToList(errorPhoneList, predictCallDetailList);
                    needDeletePhoneIdList.addAll(errorPhoneIdList);
                }
                if (CollectionUtil.isNotEmpty(needDeletePhoneIdList)) {
                    predictCallDbService.deleteDetail(Wrappers.<GzxPredictCallDetail>lambdaUpdate().in(GzxPredictCallDetail::getId, needDeletePhoneIdList));
                }
                //修改为待开始
                predictCallDbService.update(Wrappers.<GzxPredictCall>lambdaUpdate()
                        .set(GzxPredictCall::getBatchStatus, GzxCallBatchStatusEnum.PENDING.getCode())
                        .set(GzxPredictCall::getTotalCount, predictCallDetailList.size() - needDeletePhoneIdList.size())
                        .eq(GzxPredictCall::getBatchNumber, entry.getKey()));
            }
        }
    }

    private List<GzxPhoneStatusDto> verifyComplaintPhone(List<String> phoneList, String userId, String tenantId) {
        List<List<String>> batchList = Lists.partition(phoneList, IntConstant.VALUE_2000);
        List<GzxPhoneStatusDto> resultList = new ArrayList<>();
        batchList.forEach(s -> resultList.addAll(complaintPhoneService.verifyComplaint(s, userId, tenantId)));
        return resultList;
    }

    private List<GzxPhoneStatusDto> verifyErrorPhone(List<String> phoneList, String userId, String tenantId) {
        List<List<String>> batchList = Lists.partition(phoneList, IntConstant.VALUE_2000);
        List<GzxPhoneStatusDto> resultList = new ArrayList<>();
        batchList.forEach(s -> resultList.addAll(errorPhoneService.verifyPhone(s, userId, tenantId)));
        return resultList;
    }

    private Map<Integer, List<Long>> phoneToList(Map<Integer, List<String>> complaintPhoneMap, List<GzxPredictCallDetail> predictCallDetailList) {
        Map<Integer, List<Long>> typeToIdMap = new HashMap<>();
        // 先创建一个手机号到ID的反向映射
        Map<String, Long> phoneToIdMap = predictCallDetailList.stream()
                .collect(Collectors.toMap(
                        GzxPredictCallDetail::getLiaisonPhone,
                        GzxPredictCallDetail::getId,
                        (existing, replacement) -> existing));
        // 转换complaintPhoneMap中的手机号转为ID
        complaintPhoneMap.forEach((type, phones) -> {
            List<Long> ids = phones.stream()
                    .map(phoneToIdMap::get)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
            typeToIdMap.put(type, ids);
        });
        return typeToIdMap;
    }

    private List<Long> phoneToList(List<String> errorPhoneList, List<GzxPredictCallDetail> predictCallDetailList) {
        // 先创建手机号到ID的映射
        Map<String, Long> phoneToIdMap = predictCallDetailList.stream()
                .collect(Collectors.toMap(
                        GzxPredictCallDetail::getLiaisonPhone,
                        GzxPredictCallDetail::getId,
                        (existing, replacement) -> existing
                ));
        return errorPhoneList.stream()
                .map(phoneToIdMap::get)
                .filter(Objects::nonNull)
                .toList();
    }
}
